package stud.mpgame.network;

import flash.utils.TypedDictionary;

import stud.mpgame.network.Message;
import stud.mpgame.network.IMessageDispatcher;
import stud.mpgame.network.NetworkMonitor;

import stud.mpgame.network.util.ResponseMessageDescription;
import stud.mpgame.network.util.ResponseUserObject;

/**
 * ...
 * @author Timofeev, pavel[f.pavel91@gmail.com]
 */

class MessageDispatcher implements IMessageDispatcher {
    
    private var receivedListeners:List< Message -> Void >;
    private var descriptionReceivedListeners:TypedDictionary< MessageDescription, List< Message -> Void> >;
    private var sentListeners:List< Message -> Void >;
    private var descriptionSentListeners:TypedDictionary< MessageDescription, List< Message -> Void > >;
    
    private var networkMonitor:NetworkMonitor;
    
    public function new(networkMonitor:NetworkMonitor) {
        this.networkMonitor = networkMonitor;
        receivedListeners = new List< Message -> Void>();
        descriptionReceivedListeners = new TypedDictionary< MessageDescription, List< Message -> Void > >();
        sentListeners = new List< Message -> Void >();
        descriptionSentListeners = new TypedDictionary< MessageDescription, List< Message -> Void > >();
    }
    
    public function addMessageReceivedListener(messageDescription:MessageDescription, listener:Message-> Void):Void {
        if (messageDescription == null) {
			receivedListeners.add(listener);
			return;
		}
		var currentListeners:List< Message -> Void > = descriptionReceivedListeners.get(messageDescription);
        if (currentListeners == null) {
            currentListeners = new List< Message -> Void >();           
        }
        currentListeners.add(listener);
        descriptionReceivedListeners.set(messageDescription, currentListeners);
    }
    
    public function addMessageSentListener(messageDescription:MessageDescription, listener:Message -> Void):Void {
        if (messageDescription == null) {
			sentListeners.add(listener);
			return;
		}        
		var currentListeners:List< Message -> Void > = descriptionSentListeners.get(messageDescription);
        if (currentListeners == null) {
            currentListeners = new List< Message -> Void >();           
        }
        currentListeners.add(listener);
        descriptionSentListeners.set(messageDescription, currentListeners);
    }
    
    public function removeMessageReceivedListener(messageDescription:MessageDescription, listener:Message -> Void):Void {
        descriptionReceivedListeners.get(messageDescription).remove(listener);
    }
    
    public function removeMessageSentListener(messageDescription:MessageDescription, listener:Message -> Void):Void {
        descriptionSentListeners.get(messageDescription).remove(listener);
    }
    
    public function messageReceived(message:Message):Void {
        for (currentListener in receivedListeners) {
            currentListener(message);
        }
        var messageDescription:MessageDescription = getMessageDescription(message);
        if (messageDescription.isAutoResponseFlag()) {
            var responseMessageDescription:MessageDescription = ResponseMessageDescription.getInstance();
            var responseMessage:Message = new Message(networkMonitor, responseMessageDescription);            
            var responseUserObject:UserObject = new ResponseUserObject(messageDescription, message.getSerialNumber(), message.getSentTime(), message.getReceivedTime());
            responseMessage.putUserObject(responseUserObject);            
            responseMessage.send();
        }
        var currentListeners:List< Message -> Void > = descriptionReceivedListeners.get(messageDescription);
        if (currentListeners != null) {
            for (currentListener in currentListeners) {
                currentListener(message);
            }
        }
    }
    
    public function messageSent(message:Message):Void {        
        for (currentListener in sentListeners) {
            currentListener(message);
        }
        var messageDescription:MessageDescription = getMessageDescription(message);
        var currentListeners:List< Message -> Void > = descriptionSentListeners.get(messageDescription);
        if (currentListeners != null) {
            for (currentListener in currentListeners) {
                currentListener(message);
            }
        }
    }
	
    private function getMessageDescription(message:Message):MessageDescription {
        var messageDescription:MessageDescription  = message.getMessageDescription();
        if(messageDescription.equals(ResponseMessageDescription.getInstance())) {
            //find description of ResponseMessage
            var responseUserObject:ResponseUserObject = cast(message.getUserObject(ResponseUserObject), ResponseUserObject);
            messageDescription = responseUserObject.getMessageDescription();
        }
        return messageDescription;
    }	
    
}